#include "ConcreteViewport.h"
#include "Metagraphics.h"
#include "SDL_opengl.h"
#include <iostream>

namespace k2graphics
{

ConcreteViewport::ConcreteViewport()
{
	// defaults to taking up the entire screen

	screen_x = 0.0;
	screen_y = 0.0;
	screen_width = 1.0;
	screen_height = 1.0;
}

ConcreteViewport::ConcreteViewport(float sx, float sy, float sw, float sh)
{
	screen_x = sx;
	screen_y = sy;
	screen_width = sw;
	screen_height = sh;
}

void ConcreteViewport::setPosition(float nx, float ny)
{
	screen_x = nx;
	screen_y = ny;
}

void ConcreteViewport::setDimensions(float nw, float nh)
{
	screen_width = nw;
	screen_height = nh;
}

void RDToLuaTable(RenderData* rd, int layer, lua_State* L)
{
	// first, make the result table
	lua_newtable(L);
	// indicate its target
	lua_pushinteger(L, rd->renderTarget);
	lua_setfield(L, -2, "target");
	// layer
	lua_pushinteger(L, layer);
	lua_setfield(L, -2, "layer");
	// number of ints
	lua_pushinteger(L, rd->numInts);
	lua_setfield(L, -2, "numI");
	// num bytes
	lua_pushinteger(L, rd->numBytes);
	lua_setfield(L, -2, "numB");
	// num floats
	lua_pushinteger(L, rd->numFloats);
	lua_setfield(L, -2, "numF");

	// now just the new table should be at the top of the stack...
	// build the int table
	if(rd->numInts > 0)
	{
		lua_newtable(L);
		for(int i = 0; i < rd->numInts; ++i)
		{
			lua_pushinteger(L, rd->intData[i]);
			lua_rawseti(L, -2, i+1);
		}
		lua_setfield(L, -2, "intData");
	}

	// build the bytes table
	if(rd->numBytes > 0)
	{
		lua_newtable(L);
		for(int i = 0; i < rd->numBytes; ++i)
		{
			lua_pushinteger(L, rd->byteData[i]);
			lua_rawseti(L, -2, i+1);
		}
		lua_setfield(L, -2, "byteData");
	}

	// build the floats table
	if(rd->numFloats > 0)
	{
		lua_newtable(L);
		for(int i = 0; i < rd->numFloats; ++i)
		{
			lua_pushnumber(L, rd->floatData[i]);
			lua_rawseti(L, -2, i+1);
		}
		lua_setfield(L, -2, "floatData");
	}
}

void ConcreteViewport::renderViewport(double dt, AbstractViewport* srcport, GraphicsInternals* gi)
{
	//std::cout << "Rendering viewport...\n";

	// first, set our viewport
	int sx = (int)(screen_x * gi->screenHeight);
	int sy = (int)(screen_y * gi->screenHeight);
	int sw = (int)(screen_width * gi->screenHeight);
	int sh = (int)(screen_height * gi->screenHeight);
	glViewport(sx, sy, sw, sh);

	// extract some info from the source abstract viewport
	int numSettings = srcport->getNumSettings();
	float* avps = srcport->getSettings();

	float avx = avps[0];
	float avy = avps[1];
	float ravhw = avps[2] / 2.0;
	float ravhh = avps[3] / 2.0;
	float avhw;
	float avhh;
	int numLayers = (int)(avps[4]);

	// preemptively get the renderer array
	Renderer** renderers = Metagraphics::getMetagraphics()->getRenderers();

	// now render the layers in order
	for(int i = 0; i < numLayers; ++i)
	{
		// figure out where the current layer position is..
		RenderLayer* curLayer = srcport->getLayer(i);

		float curX = curLayer->invLayerParallax * avx;
		float curY = curLayer->invLayerParallax * avy;

		switch(curLayer->sizeMode)
		{
		case SIZE_MODE_MULTIPLY:
			avhw = ravhw * curLayer->hw;
			avhh = ravhh * curLayer->hh;
			break;
		case SIZE_MODE_ABSOLUTE:
			avhw = curLayer->hw;
			avhh = curLayer->hh;
			break;
		default:
			avhw = ravhw;
			avhh = ravhh;
			break;
		}

		// set our projection matrix to center the viewport there...
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(curX - avhw, curX + avhw, curY + avhh, curY - avhh, 1.0, -1.0);

		RenderData* curData;
		int curTarget;

		// render everything!
		// first, render abstract viewport inherited objects in this layer
		//td::cout << curLayer->numObjects << " objects to render.\n";
		for(int j = 0; j < curLayer->numObjects; ++j)
		{
			curData = curLayer->objects[j];
			curTarget = curData->renderTarget;
			//std::cout << "cur target: " << curTarget << std::endl;

			renderers[curTarget]->renderObject(curData, gi);
		}
	}
}

}